//
// ********************************************************************
// * License and Disclaimer                                           *
// *                                                                  *
// * The  Geant4 software  is  copyright of the Copyright Holders  of *
// * the Geant4 Collaboration.  It is provided  under  the terms  and *
// * conditions of the Geant4 Software License,  included in the file *
// * LICENSE and available at  http://cern.ch/geant4/license .  These *
// * include a list of copyright holders.                             *
// *                                                                  *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work  make  any representation or  warranty, express or implied, *
// * regarding  this  software system or assume any liability for its *
// * use.  Please see the license in the file  LICENSE  and URL above *
// * for the full disclaimer and the limitation of liability.         *
// *                                                                  *
// * This  code  implementation is the result of  the  scientific and *
// * technical work of the GEANT4 collaboration.                      *
// * By using,  copying,  modifying or  distributing the software (or *
// * any work based  on the software)  you  agree  to acknowledge its *
// * use  in  resulting  scientific  publications,  and indicate your *
// * acceptance of all terms of the Geant4 Software license.          *
// ********************************************************************
//
//
/// \file optical/wls/src/WLSMaterials.cc
/// \brief Implementation of the WLSMaterials class
//
//
#include "WLSMaterials.hh"

#include "G4NistManager.hh"
#include "G4SystemOfUnits.hh"

WLSMaterials *WLSMaterials::fInstance = nullptr;

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

WLSMaterials::WLSMaterials()
{
  fNistMan = G4NistManager::Instance();
  fNistMan->SetVerbose(2);

  CreateMaterials();
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

WLSMaterials::~WLSMaterials()
{
  delete fAir;
  delete fPMMA;
  delete fPethylene;
  delete fFPethylene;
  delete fPolystyrene;
  delete fSilicone;
  delete fCoating;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

WLSMaterials *WLSMaterials::GetInstance()
{
  if (!fInstance)
  {
    fInstance = new WLSMaterials();
  }
  return fInstance;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

G4Material *WLSMaterials::GetMaterial(const G4String material)
{
  G4Material *mat = fNistMan->FindOrBuildMaterial(material);

  if (!mat)
    mat = G4Material::GetMaterial(material);
  if (!mat)
  {
    G4ExceptionDescription ed;
    ed << "Material " << material << " not found!";
    G4Exception("WLSMaterials::GetMaterial", "", FatalException, ed);
  }

  return mat;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void WLSMaterials::CreateMaterials()
{
  G4double density;
  G4int ncomponents;
  G4double fractionmass;
  std::vector<G4int> natoms;
  std::vector<G4double> fractionMass;
  std::vector<G4String> elements;

  // Materials Definitions
  // =====================

  //--------------------------------------------------
  // Vacuum
  //--------------------------------------------------

  fNistMan->FindOrBuildMaterial("G4_Galactic");

  //--------------------------------------------------
  // Air
  //--------------------------------------------------

  fAir = fNistMan->FindOrBuildMaterial("G4_AIR");
  //--------------------------------------------------
  // Aluminium
  //--------------------------------------------------

  fNistMan->FindOrBuildMaterial("G4_Al");
  //--------------------------------------------------
  // PMMA(涂层)
  //--------------------------------------------------

  elements.push_back("C");
  natoms.push_back(5);
  elements.push_back("H");
  natoms.push_back(8);
  elements.push_back("O");
  natoms.push_back(2);

  density = 1.190 * g / cm3;

  fPMMA = fNistMan->ConstructNewMaterial("PMMA", elements, natoms, density);

  elements.clear();
  natoms.clear();
  //--------------------------------------------------
  // Silicone (Template for Optical Grease)硅树脂
  //--------------------------------------------------

  elements.push_back("C");
  natoms.push_back(2);
  elements.push_back("H");
  natoms.push_back(6);

  density = 1.060 * g / cm3;

  fSilicone = fNistMan->ConstructNewMaterial("Silicone", elements, natoms, density);

  elements.clear();
  natoms.clear();

  //--------------------------------------------------
  // Polystyrene（光纤核心）
  //--------------------------------------------------

  elements.push_back("C");
  natoms.push_back(8);
  elements.push_back("H");
  natoms.push_back(8);

  density = 1.050 * g / cm3;

  fPolystyrene =
      fNistMan->ConstructNewMaterial("Polystyrene", elements, natoms, density);

  elements.clear();
  natoms.clear();

  // ------------ Generate & Add Material Properties Table ------------
  //

  std::vector<G4double> energy = {
      2.00 * eV, 2.03 * eV, 2.06 * eV, 2.09 * eV, 2.12 * eV, 2.15 * eV, 2.18 * eV, 2.21 * eV, 2.24 * eV, 2.27 * eV,
      2.30 * eV, 2.33 * eV, 2.36 * eV, 2.39 * eV, 2.42 * eV, 2.45 * eV, 2.48 * eV, 2.51 * eV, 2.54 * eV, 2.57 * eV,
      2.60 * eV, 2.63 * eV, 2.66 * eV, 2.69 * eV, 2.72 * eV, 2.75 * eV, 2.78 * eV, 2.81 * eV, 2.84 * eV, 2.87 * eV,
      2.90 * eV, 2.93 * eV, 2.96 * eV, 2.99 * eV, 3.02 * eV, 3.05 * eV, 3.08 * eV, 3.11 * eV, 3.14 * eV, 3.17 * eV,
      3.20 * eV, 3.23 * eV, 3.26 * eV, 3.29 * eV, 3.32 * eV, 3.35 * eV, 3.38 * eV, 3.41 * eV, 3.44 * eV, 3.47 * eV};
  // 波长:620nm-357nm
  std::vector<G4double> energySmall = {2.0 * eV, 3.47 * eV};

  //--------------------------------------------------
  // Air
  //--------------------------------------------------

  std::vector<G4double> refractiveIndex = {1.0, 1.0};
  auto mpt = new G4MaterialPropertiesTable();
  mpt->AddProperty("RINDEX", energySmall, refractiveIndex); // 折射率
  fAir->SetMaterialPropertiesTable(mpt);

  //--------------------------------------------------
  //  PMMA(涂层)
  //--------------------------------------------------

  std::vector<G4double> refractiveIndexClad1 = {1.49, 1.49};
  std::vector<G4double> absClad1 = {4. * m, 4. * m};
  // std::vector<G4double> absClad1 = {15.5 * cm, 15.5 * cm};
  // std::vector<G4double> absClad1 = {2. * cm, 2. * cm};

  // Add entries into properties table
  auto Clad1 = new G4MaterialPropertiesTable();
  Clad1->AddProperty("RINDEX", energySmall, refractiveIndexClad1); // 折射率
  Clad1->AddProperty("ABSLENGTH", energySmall, absClad1);          // 吸收长度

  fPMMA->SetMaterialPropertiesTable(Clad1);
  //--------------------------------------------------
  // Silicone 硅树脂
  //--------------------------------------------------

  std::vector<G4double> refractiveIndexSilicone = {1.46, 1.46};

  // Add entries into properties table
  auto mptSilicone = new G4MaterialPropertiesTable();
  mptSilicone->AddProperty("RINDEX", energySmall, refractiveIndexSilicone);
  mptSilicone->AddProperty("ABSLENGTH", energySmall, absClad1);

  fSilicone->SetMaterialPropertiesTable(mptSilicone);
  //--------------------------------------------------
  //  Polystyrene 聚苯乙烯（光纤核心）
  //--------------------------------------------------

  std::vector<G4double> refractiveIndexPS = {1.59, 1.59};
  std::vector<G4double> absPS = {4. * m, 4. * m};
  std::vector<G4double> scintilFast = {
      0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.01, 0.01, 0.02, 0.02,
      0.03, 0.03, 0.04, 0.05, 0.06, 0.07, 0.09, 0.10, 0.13, 0.15,
      0.18, 0.22, 0.26, 0.31, 0.36, 0.43, 0.49, 0.56, 0.64, 0.71,
      0.78, 0.85, 0.91, 0.97, 1.00, 0.99, 0.94, 0.76, 0.46, 0.21,
      0.08, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00};
  // WLS
  std::vector<G4double> absWLSfiber = {
      5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m,
      5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m,
      5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 1.10 * m,
      1.10 * m, 1.10 * m, 1.10 * m, 1.10 * m, 1.10 * m, 1.10 * m, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm,
      1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm};
  std::vector<G4double> emissionFib = {
      0.05, 0.10, 0.30, 0.50, 0.75, 1.00, 1.50, 1.85, 2.30, 2.75,
      3.25, 3.80, 4.50, 5.20, 6.00, 7.00, 8.50, 9.50, 11.1, 12.4,
      12.9, 13.0, 12.8, 12.3, 11.1, 11.0, 12.0, 11.0, 17.0, 16.9,
      15.0, 9.00, 2.50, 1.00, 0.05, 0.00, 0.00, 0.00, 0.00, 0.00,
      0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00};
  // Add entries into properties table
  auto mptPolystyrene = new G4MaterialPropertiesTable();
  // 添加随波长变化的光学属性 添加本征属性
  mptPolystyrene->AddProperty("RINDEX", energySmall, refractiveIndexPS);       // 折射率
  mptPolystyrene->AddProperty("ABSLENGTH", energySmall, absPS);                // 吸收长度
  mptPolystyrene->AddProperty("SCINTILLATIONCOMPONENT1", energy, scintilFast); // 发射光谱
  // mptPolystyrene->AddProperty("WLSABSLENGTH", energy, absPS);
  // mptPolystyrene->AddProperty("WLSCOMPONENT", energy, emissionFib);
  // mptPolystyrene->AddConstProperty("WLSTIMECONSTANT", 0.5 * ns);
  mptPolystyrene->AddConstProperty("SCINTILLATIONYIELD", 8000 / MeV);       // 光产额
  mptPolystyrene->AddConstProperty("RESOLUTIONSCALE", 1.0);                 // 本征分辨
  mptPolystyrene->AddConstProperty("SCINTILLATIONTIMECONSTANT1", 2.8 * ns); // 衰减时间常数
  mptPolystyrene->AddConstProperty("SCINTILLATIONYIELD1", 1.);              // 相对产率
  fPolystyrene->SetMaterialPropertiesTable(mptPolystyrene);

  // Set the Birks Constant for the Polystyrene scintillator
  fPolystyrene->GetIonisation()->SetBirksConstant(0.126 * mm / MeV);
}
